package com.r2coding.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.r2coding.constant.Constant;
import com.r2coding.entity.UsersEntity;
import com.r2coding.enums.AuthResultEnum;
import com.r2coding.util.JwtUtil;
import com.r2coding.util.Result;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

/**
 * @author: 98k灬
 * @since: 2022/11/01
 * @email: 98k_style@sina.com
 * @公众号: 爪哇Guy灬
 **/
@Slf4j
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Resource
    RedisTemplate redisTemplate;

    @Resource
    ObjectMapper objectMapper;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {
        String token = request.getHeader(Constant.ACCESS_TOKEN);
        if (StringUtils.isEmpty(token)) {
            if (!request.getRequestURI().equals(Constant.LOGIN_URI) &&
                    !request.getRequestURI().equals(Constant.MOBILE_LOGIN_URI) &&
                    !request.getRequestURI().equalsIgnoreCase("/mobile/code")) {
                this.writeResp(AuthResultEnum.UNAUTHENTICATED.getCode(), AuthResultEnum.UNAUTHENTICATED.getDesc(), response);
                return;
            }
            chain.doFilter(request, response);
            return;
        }

        String userId;
        try {
            Claims claims = JwtUtil.parseJWT(token);
            userId = claims.getSubject();
        } catch (Exception exception) {
            log.error("JwtAuthenticationTokenFilter error : " + exception.getMessage());
            this.writeResp(AuthResultEnum.TOKEN_ERROR.getCode(), AuthResultEnum.TOKEN_ERROR.getDesc(), response);
            return;
        }

        // 从Redis中获取用户信息
        String redisKey = Constant.LOGIN_KEY + userId;
        Object redisValue = redisTemplate.opsForValue().get(redisKey);
        if (Objects.isNull(redisValue)) {
            this.writeResp(AuthResultEnum.TOKEN_PAST.getCode(), AuthResultEnum.TOKEN_PAST.getDesc(), response);
            return;
        }
        UsersEntity user = (UsersEntity) redisValue;
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, null, null);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        chain.doFilter(request, response);
    }

    private void writeResp(Integer code, String desc, HttpServletResponse response) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        Result msg = Result.build(code, desc);
        String json = objectMapper.writeValueAsString(msg);
        response.getWriter().write(json);
    }
}
